﻿// Copyright (c) Autofac Project. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Autofac.Builder;
using Autofac.Core;
using Autofac.Features.LightweightAdapters;

namespace Autofac;

/// <summary>
/// Adds registration syntax to the <see cref="ContainerBuilder"/> type.
/// </summary>
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
public static partial class RegistrationExtensions
{
    /// <summary>
    /// Adapt all components implementing service <typeparamref name="TFrom"/>
    /// to provide <typeparamref name="TTo"/> using the provided <paramref name="adapter"/>
    /// function.
    /// </summary>
    /// <typeparam name="TFrom">Service type to adapt from.</typeparam>
    /// <typeparam name="TTo">Service type to adapt to. Must not be the
    /// same as <typeparamref name="TFrom"/>.</typeparam>
    /// <param name="builder">Container builder.</param>
    /// <param name="adapter">Function adapting <typeparamref name="TFrom"/> to
    /// service <typeparamref name="TTo"/>, given the context and parameters.</param>
    public static IRegistrationBuilder<TTo, LightweightAdapterActivatorData, DynamicRegistrationStyle>
        RegisterAdapter<TFrom, TTo>(
            this ContainerBuilder builder,
            Func<IComponentContext, IEnumerable<Parameter>, TFrom, TTo> adapter)
        where TFrom : notnull
        where TTo : notnull
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        if (adapter == null)
        {
            throw new ArgumentNullException(nameof(adapter));
        }

        return LightweightAdapterRegistrationExtensions.RegisterAdapter(builder, adapter);
    }

    /// <summary>
    /// Adapt all components implementing service <typeparamref name="TFrom"/>
    /// to provide <typeparamref name="TTo"/> using the provided <paramref name="adapter"/>
    /// function.
    /// </summary>
    /// <typeparam name="TFrom">Service type to adapt from.</typeparam>
    /// <typeparam name="TTo">Service type to adapt to. Must not be the
    /// same as <typeparamref name="TFrom"/>.</typeparam>
    /// <param name="builder">Container builder.</param>
    /// <param name="adapter">Function adapting <typeparamref name="TFrom"/> to
    /// service <typeparamref name="TTo"/>, given the context.</param>
    public static IRegistrationBuilder<TTo, LightweightAdapterActivatorData, DynamicRegistrationStyle>
        RegisterAdapter<TFrom, TTo>(
            this ContainerBuilder builder,
            Func<IComponentContext, TFrom, TTo> adapter)
        where TFrom : notnull
        where TTo : notnull
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        if (adapter == null)
        {
            throw new ArgumentNullException(nameof(adapter));
        }

        return builder.RegisterAdapter<TFrom, TTo>((c, p, f) => adapter(c, f));
    }

    /// <summary>
    /// Adapt all components implementing service <typeparamref name="TFrom"/>
    /// to provide <typeparamref name="TTo"/> using the provided <paramref name="adapter"/>
    /// function.
    /// </summary>
    /// <typeparam name="TFrom">Service type to adapt from.</typeparam>
    /// <typeparam name="TTo">Service type to adapt to. Must not be the
    /// same as <typeparamref name="TFrom"/>.</typeparam>
    /// <param name="builder">Container builder.</param>
    /// <param name="adapter">Function adapting <typeparamref name="TFrom"/> to
    /// service <typeparamref name="TTo"/>.</param>
    public static IRegistrationBuilder<TTo, LightweightAdapterActivatorData, DynamicRegistrationStyle>
        RegisterAdapter<TFrom, TTo>(
            this ContainerBuilder builder,
            Func<TFrom, TTo> adapter)
        where TFrom : notnull
        where TTo : notnull
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        if (adapter == null)
        {
            throw new ArgumentNullException(nameof(adapter));
        }

        return builder.RegisterAdapter<TFrom, TTo>((c, p, f) => adapter(f));
    }
}
